// 声明构造函数
function Promise(executor) {
    // 添加属性
    this.PromiseState = 'pending'
    this.PromiseResult = null
    // 声明保存回调函数的对象
    this.callBacks = []
    // 保存实例对象的this的值
    const self = this
    // 声明resolve()和reject()
    function resolve(data) {
        // 判断状态(状态是否被修改过)
        if (self.PromiseState !== 'pending') {
            return
        }
        // 1. 修改对象的状态(promiseState)
        // 如果直接这么调用this会指向window;this.PromiseState = 'fulfilled'
        self.PromiseState = 'fulfilled'
        // 2. 设置对象结果值(promiseResult)
        self.PromiseResult = data
        // 如果是一个异步任务,需要在调用resolve函数的最后进行then方法的回调
        // 使用setTimeout使其变成异步任务
        setTimeout(() => {
            self.callBacks.forEach(item => {
                item.onResolved(data)
            })
        })
    }
    function reject(data) {
        // 判断状态(状态是否被修改过)
        if (self.PromiseState !== 'pending') {
            return
        }
        self.PromiseState = 'rejected'
        self.PromiseResult = data
        setTimeout(() => {
            self.callBacks.forEach(item => {
                item.onRejected(data)
            })
        })
    }
    // 捕获异常
    try {
        // 同步调用[执行器函数]
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }

}

// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
    // 用于解决保存回调函数时this的指向问题
    const self = this
    // 添加回调函数参数判断,即处理如果不传递回调函数参数的情况
    // 这块代码实现了异常穿透和值传递
    if (typeof onRejected !== 'function') {
        onRejected = reason => {
            throw reason
        }
    }
    if (typeof onResolved !== 'function') {
        onResolved = value => value
    }
    // 让then方法回返Promise对象使其支持链式调用
    return new Promise((resolve, reject) => {
        // 将相同代码进行封装
        function callback(exe) {
            try {
                let result = exe(self.PromiseResult)

                // 这里又分为两种情况一种是onResolved函数返回的是一个Promise对象,和非Promise对象
                if (result instanceof Promise) {
                    // 返回结果是一个Promise对象
                    result.then(v => {
                        resolve(v)
                    }, r => {
                        reject(r)
                    })
                } else {
                    // 返回结果是一个非Promise对象,(返回状态为成功的Promise对象)
                    resolve(result)
                }
            } catch (e) {
                reject(e)
            }
        }

        // 这里的then方法的调用者是一个Promise实例对象,所以可以使用this直接访问属性
        if (this.PromiseState === 'fulfilled') {
            setTimeout(() => {
                callback(onResolved)
            })
        }
        if (this.PromiseState === 'rejected') {
            setTimeout(() => {
                callback(onRejected)
            })
        }
        // 异步任务时执行如下代码
        // 当状态未发生变化时(pending),说明是一个异步任务
        if (this.PromiseState === 'pending') {
            // 在等待异步任务执行完成之后才能调用then方法,所以需要将回调函数保存到then的外部!
            // 这种方式只能保存一组回调函数,如果是多次调用then函数,后面的回调函数会将前面过的回调函数覆盖
            // this.callBack = {
            //     onRejected,
            //     onResolved
            // }
            this.callBacks.push({
                // 注意这里只是将两个函数进行保存,并没有执行,真正执行的地方在resolve和reject函数中
                onResolved: function () {
                    callback(onResolved)
                },
                onRejected: function () {
                    callback(onRejected)
                }
            })
        }
    })

}

// 添加catch方法,可以直接调用then方法即可
Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
}

// 添加resolve方法,这个方法是属于Promise对象的;不是属于实例的
// 这个方法根据参数类型返回不同的结果,如果参数是一个Promise对象,那么结果就是这个Promise对象的结果,如果是一个非Promise对象,那么就返回一个成功的Promise对象,
Promise.resolve = function (value) {
    return new Promise((resolve, reject) => {
        // 判断参数类型
        if (value instanceof Promise) {
            value.then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
        } else {
            // 非Promise对象
            resolve(value)
        }
    })
}

// 添加reject方法,这个方法永远返回一个失败的Promise对象
Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason)
    })
}

// 添加all方法
Promise.all = function (promises) {
    // 返回结果为promise对象
    return new Promise((resolve, reject) => {
        // 声明一个记录成功次数的变量count
        let count = 0
        // 声明一个存放成功结果的数组arr
        let arr = []
        // 遍历参数
        for (let i = 0, length = promises.length; i < length; i++) {
            // 执行promise对象的回调函数then
            promises[i].then(v => {
                // 这里不能直接调用resolve方法,
                // 累加count计数
                count++
                // 将成功的结果存入arr
                arr[i] = v
                // 如果count与参数长度相等,说明全部为成功的Promise
                if (count === length) {
                    // 调用resolve方法
                    resolve(arr)
                }
            }, r => {
                reject(r)
            })
        }
    })
}

// 添加race方法
Promise.race = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i = 0, length = promises.length; i < length; i++) {
            // 执行promise对象的回调函数then
            promises[i].then(v => {
                // 直接调用resolve方法即可,哪个先执行完成哪个先执行这个resolve
                resolve(arr)
            }, r => {
                reject(r)
            })
        }
    })
}
